﻿using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Threading.Tasks;

namespace Core.DataAccess.Model
{

    public static class PaginationExtent
    {
        public static async Task<List<TSource>> ToListAsyncOfAsNoTracking<TSource>(this IQueryable<TSource> source)
            where TSource : class
        {
            return await source.AsNoTracking().ToListAsync();
        }

        /// <summary>
        /// 分页通用参数查询
        /// </summary>
        /// <typeparam name="TSource"></typeparam>
        /// <param name="source"></param>
        /// <param name="pagination"></param>
        /// <returns></returns>
        public static async Task<List<TSource>> PaginationAsync<TSource>(this IQueryable<TSource> source, Pagination pagination)
            where TSource : class
        {

            if (pagination == default) return await source.AsNoTracking().ToListAsync();


            if (!string.IsNullOrWhiteSpace(pagination?.sidx))
            {
                var param = Expression.Parameter(typeof(TSource), "t");

                // 是否倒序排列
                var isDesc = pagination.sord.ToLower().Equals("desc");


                var sidxs = pagination.sidx.Split(",");


                if (sidxs.Length == 1)
                {
                    var body = Expression.Property(param, pagination.sidx);

                    Expression<Func<TSource, object>> keySelector =
                        Expression.Lambda<Func<TSource, object>>(Expression.Convert(body, typeof(object)), param);

                    if (isDesc)
                        source = source.OrderByDescending(keySelector);
                    else
                        source = source.OrderBy(keySelector);

                }
                else
                {

                    IOrderedQueryable<TSource> iOrderedQueryable;

                    {
                        var body = Expression.Property(param, sidxs[0]);

                        Expression<Func<TSource, object>> keySelector =
                            Expression.Lambda<Func<TSource, object>>(Expression.Convert(body, typeof(object)), param);

                        if (isDesc)
                            iOrderedQueryable = source.OrderByDescending(keySelector);
                        else
                            iOrderedQueryable = source.OrderBy(keySelector);

                    }


                    foreach (var item in sidxs)
                    {
                        if (item != sidxs.First())
                        {
                            var body = Expression.Property(param, item);

                            Expression<Func<TSource, object>> keySelector =
                                Expression.Lambda<Func<TSource, object>>(Expression.Convert(body, typeof(object)), param);

                            if (isDesc)
                                iOrderedQueryable = iOrderedQueryable.ThenByDescending(keySelector);
                            else
                                iOrderedQueryable = iOrderedQueryable.ThenBy(keySelector);
                        }

                    }

                    source = iOrderedQueryable;

                }



            }

            if (pagination?.rows > 0)
            {
                pagination.records = source.Count();
                source = source.Skip(pagination.rows * (pagination.page > 0 ? pagination.page - 1 : 0));
                source = source.Take(pagination.rows);
            }

            return await source.AsNoTracking().ToListAsync();
        }
    }

    /// <summary>
    /// 分页实体
    /// </summary>
    public class Pagination
    {
        /// <summary>
        /// 每页行数
        /// </summary>
        public int rows { get; set; }

        /// <summary>
        /// 当前页
        /// </summary>
        public int page { get; set; }

        /// <summary>
        /// 排序列
        /// </summary>
        public string sidx { get; set; }

        /// <summary>
        /// 排序类型
        /// </summary>
        public string sord { get; set; }

        /// <summary>
        /// 总记录数
        /// </summary>
        public int records { get; set; }

        /// <summary>
        /// 总页数
        /// </summary>
        public int total
        {
            get
            {
                if (records > 0)
                {
                    return records % this.rows == 0 ? records / this.rows : records / this.rows + 1;
                }
                else
                {
                    return 0;
                }
            }
        }
    }

}
